
import fs from 'fs/promises'
import path from 'path';
import { normalizePath } from 'vite';
import fastGlob, { async } from 'fast-glob';
import { runTimeTpl } from '@/utils';

const topologicalSort = (models) => {
  // build depts graph
  const graph = [];
  const namespaceToNode = {};

  models.forEach((model, index) => {
    const node = {
      namespace: model.namespace,
      deps: model.deps,
      index,
      in: 0,
      childs: [],
    };

    if (namespaceToNode[model.namespace]) {
      throw new Error(`Duplicate namespace in models: ${model.namespace}`);
    }
    namespaceToNode[model.namespace] = node;
    graph.push(node);
  });

  // build edges.
  graph.forEach((node) => {
    node.deps.forEach((dep) => {
      const depNode = namespaceToNode[dep];
      if (!depNode) {
        throw new Error(`Model namespace not found: ${dep}`);
      }
      depNode.childs.push(node);
      node.in++;
    });
  });

  const queue = [];
  while (true) {
    // find first 0 in node;
    const zeronode = graph.find((n) => {
      return n && n.in === 0;
    });
    if (!zeronode) {
      break;
    }

    queue.push(zeronode.namespace);
    zeronode.childs.forEach((child) => {
      child.in--;
    });
    zeronode.childs = [];
    delete graph[zeronode.index];
  }

  const leftNodes = graph.filter(Boolean);
  if (leftNodes.length > 0) {
    throw new Error(`Circle dependency detected in models`);
  }

  return queue;
};
export default function rollupPluginModels() {

  return {
    name: 'rollupPluginModels',
 
    
    configureServer() {
  
         
    },
    buildStart() {
      const entries = fastGlob.globSync('*.ts',{ absolute: true,cwd:path.join(process.cwd(),'src/models') });
      console.time('END');
      const pattern = /useModel\(.*?\s*?'\s*([a-z0-9]+)/gi;

       Promise.all(entries.map(async (entry) =>{
         const content= await  fs.readFile(normalizePath(entry),{encoding: 'utf8'});
         let match;
         const deps = new Set();
         while ((match = pattern.exec(content))) {
           deps.add(match[1]);
         }
         return  {
           namespace:path.basename(entry).split(path.extname(entry))[0],
           filePath:entry,
           deps: Array.from(deps),
         };;
      })).then(result =>{
        console.timeEnd("END");
        const namespaces=topologicalSort(result);
        result= result.sort(
          (a, b) =>
            namespaces.indexOf(a.namespace) - namespaces.indexOf(b.namespace),
        );
        console.log(result);
        const modelImports =
        result
          .map((model) => {
            return `import ${model.namespace} from "${normalizePath(
              model.filePath
            )}";`;
          }).join("\n");
           
          const data=result
          .map((model) => {
            return `'${model.namespace}':${model.namespace}`;
          });
          runTimeTpl({
            name:'plugin-models',
            fileName: 'models.ts',
            content:`${modelImports}\nexport default {${data.join(',')}}`
       });
      });
    },
 
  };
}
